package server;

import client.GenericClientOnServer;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Classe per la gestione del server. Il server contiene un pool di utenti e una mappa di smiles. Ad ogni nuovo utente
 * viene generato un apposito thread dedicato e gestito da un {@link ExecutorService} con un pool di 32 Thread.
 * @author Claudio "Dna" Bonesana
 */
public class HTTPServer extends Thread{

	private int port = 4700;
	private int connId = 0;

	private ArrayList<GenericClientOnServer> users = new ArrayList<GenericClientOnServer>();
    private Map<String, String> smiles = new HashMap<String, String>();

    /**
     * Con questo costruttore viene assegnata la nuova porta e popolata la mappa degli smiles con lo smile ":>".
     * @param port  porta di ascolto del server
     */
    public HTTPServer(int port) {
		this.port = port;

        smiles.put(":>","http://i.imgur.com/I9dLPZK.gif");
	}

    /**
     * Esegue il server. Viene istanziato un nuovo {@link ServerSocket}, una {@link KickRoutine} e un {@link ExecutorService}
     * di 32 thread. Ad ogni nuovo client che si connette viene costruito un {@link GenericClientOnServer} che viene inserito
     * nel {@link ExecutorService}.
     */
    @Override
	public void run(){
		try {
			ServerSocket server = new ServerSocket(port);
            KickRoutine kickRoutine = new KickRoutine(this);
			ExecutorService execServ = Executors.newFixedThreadPool(32);

            execServ.submit(kickRoutine);

			System.out.println("In ascolto su porta " + 4700);
			System.out.println("In attesa di connessioni...");
			
			while(true){
                GenericClientOnServer genericClientOnServer = new GenericClientOnServer(server.accept(),++connId,this);
				users.add(genericClientOnServer);           /*  Aggiunta di un nuovo client alla lista dei client    */
				execServ.submit(genericClientOnServer);     /*  Aggiunta del client all'ExecServ e successivo inizio */
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

    /**
     * @return  la mappa degli smile
     */
    public Map<String, String> getSmiles() {
        return smiles;
    }

    /**
     * Aggiunge uno smile alla mappa
     * @param sequence  sequenza che definirà lo smile
     * @param url       link ad una risorsa esterna
     */
    public void addSmiles(String sequence, String url) {
        this.smiles.put(sequence,url);
    }

    /**
     * @return  la lista di tutti i client connessi
     */
	public ArrayList<GenericClientOnServer> getUsers() {
		return users;
	}

    /**
     * Aggiorna tutti i client connessi inviando loro il messaggio {@code message}.
     * @param message   il messaggio da inviare
     */
	public void update(String message){
		for (GenericClientOnServer user : users) {
			user.update(message);
		}
	}

    /**
     * Aggiorna tutti i client ad eccezione del client con id {@code exclude}
     * @param msg       il messaggio da inviare
     * @param exclude   il client a cui non verrà recapitato il messaggio
     */
	public void update(String msg, int exclude){
		for (GenericClientOnServer user : users) {
			if (user.getId() != exclude)
				user.update(msg);
		}
	}

    /**
     * Aggiorna un solo client indicato da {@code reciever} con un nuovo messaggio
     * @param reciever  l'unico client che riceverà il messaggio
     * @param msg       il messaggio da inviare
     */
	public void update(int reciever, String msg){
		for (GenericClientOnServer user : users) {
			if (user.getId() == reciever)
				user.update(msg);
		} 
	}

    /**
     * Elimina un client dal server e notifica tutti gli altri client del motivo
     * @param genericClientOnServer     il client da rimuovere dal server
     * @param motive                    il motivo per cui il client è stato rimosso
     */
    public void removeClient(GenericClientOnServer genericClientOnServer, String motive){
        update(motive);
        users.remove(genericClientOnServer);
    }

}
